/*
 * @Description: 基础类型
 * @Autor: HuiSir<273250950@qq.com>
 * @Date: 2021-05-06 18:39:41
 * @LastEditTime: 2021-05-20 15:58:19
 */
(function () {
    /**
     * 这里的“基础类型”非js中的“基本数据类型”，而是编译阶段的强制类型限制，一般使用`变量名:类型`来限制变量的类型，类型使用小写
     * 基础类型有：字符串、数字、布尔值、any、数组、元组、枚举、void、undefined、null、never、联合类型、对象
     * 严格模式和非严格模式会有部分出入
     * ts鼓励使用严格模式，这样能避免很多疑惑性问题
     * ts支持类型推导，可以不写类型（由于是js的超集）
     * 同一个文件夹下的ts代码不能有同名的变量，所以一般放到自执行函数中或块作用域中
     */
    /**
     * 字符串 string
     * 可以使用双引号和单引号
     * 可以使用模板字符串
     */
    var firstName = "张";
    var fullName = "".concat(firstName, "\u4E09");
    /**
     * 数字 number
     * 不区分整型和浮点型
     * 支持十进制、八进制、二进制、十六进制
     * (原生js只支持十进制和十六进制，在编译为js时会将其他进制转换为十进制)
     */
    var decLiteral = 18; //十进制
    var hexLiteral = 0xf00d; //十六进制
    var binaryLiteral = 10; //二进制
    var octalLiteral = 484; //八进制
    /**
     * 布尔值 boolean
     * 只有true和false
     */
    var isLogin = true;
    /**
     * 支持字符串和数字、字符串和布尔值拼接
     * 运算时会把非十进制的数字转换为十进制
     */
    console.log(fullName + decLiteral); //张三18
    console.log(fullName + octalLiteral); //张三484
    console.log(fullName + isLogin); //张三true
    /**
     * 任意类型any
     * 任意类型可以被赋任意类型的值，语义化和限制较少，所以不推荐
     * 当改写原生js代码时，或者未知类型的数据时，any是非常有用的
     */
    var temp = 1;
    temp = "Hello";
    /**
     * 空类型void
     * void在ts中一般用于函数的返回值（无返回值情况）
     * void类型的变量没有什么大用,在严格模式只能赋值为undefined
     * 在非严格模式下可以赋值为null和undefined
     */
    function fn() { }
    var unusable = undefined;
    // unusable = null //严格模式报错：不能将类型“null”分配给类型“void”
    /**
     * undefined和null
     * 和 void相似，它们的本身的类型用处不是很大
     * 在非严格模式下，是所有类型的子类型,可以将null和undefined赋值给任意类型
     * 在非严格模式下，null可以赋值给undefined类型，反之亦然
     * 在严格模式下，null和undefined不能互相赋值
     */
    var u = undefined;
    var n = null;
    var num = 1;
    // num = undefined //严格模式报错：不能将类型“undefined”分配给类型“number”
    // num = null  //严格模式报错：不能将类型“null”分配给类型“number”
    // u = null    //严格模式报错：不能将类型“null”分配给类型“undefined”
    // n = undefined   //严格模式报错：不能将类型“undefined”分配给类型“null”
    /**
     * never 表示的是那些永不存在的值的类型
     * never 类型一般用于抛出错误的函数的返回值
     * never 类型是任何类型的子类型，也可以赋值给任何类型
     * 没有类型是never的子类型，任何类型都不能赋值给never类型，包括any
     * 返回never的函数也可以用于死循环
     */
    // 返回never的函数为抛出错误
    function error(message) {
        throw new Error(message);
    }
    // 类型推导的返回值类型为never
    function fail() {
        return error("Something failed");
    }
    // 返回never的函数也可以用于死循环
    function infiniteLoop() {
        while (true) {
        }
    }
    // never赋值给number
    var money = 100;
    // money = fail()
    /**
     * 数组 array
     * 可以使用`number[]`或`Array<number>`定义数组类型
     * 数组的所有元素必须符合定义的统一类型
     * 可以使用any定义未知类型的数组，但一般不推荐
     */
    var list1 = [1, 2, 3];
    var list2 = [1, 2, 3];
    var list3 = ["1", "2", "3"];
    var list4 = ["1", 1, true];
    /**
     * 元组 Tuple
     * 表示一个已知元素数量和类型的数组
     */
    var x;
    x = ['hello', 10]; // OK
    console.log(x[0].substr(1)); // OK
    //  x = [10, 'hello'] // Error
    // console.log(x[1].substr(1)) // Error, 'number' does not have 'substr'
    // x[3] = 'world' //报错：长度为 "2" 的元组类型 "[string, number]" 在索引 "3" 处没有元素
    // console.log(x[5].toString()) //报错：对象可能为“未定义”。
    /**
     * 枚举
     * enum 关键字开头创建
     * 作用：为一组数值（或字符串）赋予友好的名字便于以后调用（语义化更好）
     * 枚举实际上是一个数值对象,但在ts中是只读的，所以也不能称之为引用类型
     * 枚举的数值从左往右默认依次为从0开始的整数，类似于数组下标
     * 初始化时给某个元素赋值,若为数字，则该元素之后的元素的值会依次加1
     * 可以给枚举的元素赋值为字符串
     * 可以由枚举名得到其值，也可以由值得到名字
     */
    var Color;
    (function (Color) {
        Color[Color["Red"] = 0] = "Red";
        Color[Color["Green"] = 1] = "Green";
        Color[Color["Blue"] = 2] = "Blue";
    })(Color || (Color = {}));
    var Color2;
    (function (Color2) {
        Color2[Color2["Red"] = 0] = "Red";
        Color2[Color2["Green"] = 12] = "Green";
        Color2[Color2["Blue"] = 13] = "Blue";
    })(Color2 || (Color2 = {}));
    var Color3;
    (function (Color3) {
        Color3[Color3["Red"] = 0] = "Red";
        Color3["Green"] = "12";
        Color3["Blue"] = "14";
    })(Color3 || (Color3 = {}));
    var c = Color.Green;
    var c2 = Color2.Green;
    console.log(c, c2); // 1, 12
    console.log(Color); // { '0': 'Red', '1': 'Green', '2': 'Blue', Red: 0, Green: 1, Blue: 2 }
    console.log(Color2); // { '0': 'Red', '12': 'Green', '13': 'Blue', Red: 0, Green: 12, Blue: 13 }
    console.log(Color3); // { '0': 'Red', Red: 0, Green: '12', Blue: '14' }
    // 可以由枚举的值得到它的名字
    var colorName = Color[2];
    console.log(colorName); // 显示'Green'因为上面代码里它的值是2
    // Color.Green = "11"  //报错：无法分配到 "Green" ，因为它是只读属性。
    // Color[1] = "11"  //报错：类型“typeof Color”中的索引签名仅允许读取。
    /**
     * 联合类型
     * 可以使用`|`单竖线来表示联合类型，意为可以是多个类型中的一个
     * 一般用于函数的传参
     */
    var test = 12;
    test = "zhangsan";
    test = false;
    /**
     * Object 对象类型
     * 可以使用接口对对象的字段进行限制
     */
    function getObj(obj) {
        return obj;
    }
    console.log(getObj({
        name: "zhangsan",
        age: 10,
        sex: "男"
    }));
    // { name: 'zhangsan', age: 10, sex: '男' }
    // getObj(123) // 报错：类型“number”的参数不能赋给类型“object”的参数
})();
